/*
** Copyright (C) 2009 Joshua Brent Marsh <joshua@icub3d.com>
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 3 of the License, or
** (at your option) any later version.
**  
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**  
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**  
*/

/* $Id: test_pqueue.c 32 2009-10-28 22:51:19Z joshua@icub3d.com $ */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>

#include <CUnit/Basic.h>
#include "../src/pqueue.h"

#include "test_helpers.h"
#include "test_pqueue.h"

PQueue *pqueue_min;
PQueue *pqueue_max;
PQueue *pqueue_heap;

int
init_test_pqueue_suite ()
{
  if ((pqueue_min = pqueue_create (MIN, dest_int)) == NULL)
    return 1;
  else
    {
      if ((pqueue_max = pqueue_create (MAX, dest_int)) == NULL)
	{
	  pqueue_destroy (pqueue_min);
	  return 1;
	}
      else
	{
	  if ((pqueue_heap = pqueue_create (HEAP_MIN, dest_int))
	      == NULL)
	    {
	      pqueue_destroy (pqueue_min);
	      pqueue_destroy (pqueue_max);
	      return 1;
	    }
	  else
	    return 0;
	}
    }
}

int
clean_test_pqueue_suite ()
{
  pqueue_destroy (pqueue_min);
  pqueue_destroy (pqueue_max);
  pqueue_destroy (pqueue_heap);

  return 0;
}

void
test_pqueue_enqueue ()
{
  int x, y, *cur;

  for (x = 0; x < 10; x++)
    {
      for (y = 1; y <= 3; y++)
	{
	  cur = create_int (y);
	  CU_ASSERT (pqueue_enqueue (pqueue_min, x, cur) == cur);
	  cur = create_int (y);
	  CU_ASSERT (pqueue_enqueue (pqueue_max, x, cur) == cur);
	  cur = create_int (y);
	  CU_ASSERT (pqueue_enqueue (pqueue_heap, x, cur) == cur);

	  CU_ASSERT (pqueue_size (pqueue_min) == (x * 3) + y);
	  CU_ASSERT (pqueue_size (pqueue_max) == (x * 3) + y);
	  CU_ASSERT (pqueue_size (pqueue_heap) == (x * 3) + y);
	}
      
    }
}

void
test_pqueue_peek ()
{
  CU_ASSERT (*(int *)pqueue_peek (pqueue_min) == 1);
  CU_ASSERT (*(int *)pqueue_peek (pqueue_max) == 1);
  CU_ASSERT (*(int *)pqueue_peek (pqueue_heap) == 1);
}

void
test_pqueue_dequeue ()
{
  int x, *cur;
  for (x = 0; x < 24; x++)
    {
      CU_ASSERT (pqueue_size (pqueue_min) == 30 - x);
      cur = pqueue_dequeue (pqueue_min);
      CU_ASSERT (cur != NULL);
      CU_ASSERT (*cur == (x % 3) + 1);
      free (cur);

      CU_ASSERT (pqueue_size (pqueue_max) == 30 - x);
      cur = pqueue_dequeue (pqueue_max);
      CU_ASSERT (cur != NULL);
      CU_ASSERT (*cur == (x % 3) + 1);
      free (cur);

      CU_ASSERT (pqueue_size (pqueue_heap) == 30 - x);
      cur = pqueue_dequeue (pqueue_heap);
      CU_ASSERT (cur != NULL);
      free (cur);
    }
}

void
test_pqueue_enqueue2 ()
{
  int x, y, *cur;

  for (x = 0; x < 10; x++)
    {
      for (y = 7; y <= 9; y++)
	{
	  cur = create_int (y);
	  CU_ASSERT (pqueue_enqueue (pqueue_min, x, cur) == cur);
	  cur = create_int (y);
	  CU_ASSERT (pqueue_enqueue (pqueue_max, x, cur) == cur);
	  cur = create_int (y);
	  CU_ASSERT (pqueue_enqueue (pqueue_heap, x, cur) == cur);


	  CU_ASSERT (pqueue_size (pqueue_min) == (x * 3) + 4 - (10 % y) + 6);
	  CU_ASSERT (pqueue_size (pqueue_heap) == (x * 3) + 4 - (10 % y) + 6);
	  CU_ASSERT (pqueue_size (pqueue_max) == (x * 3) + 4 - (10 % y) + 6);
	}
    }
}

void
test_pqueue_dequeue2 ()
{
  int x, y, *cur;
  for (x = 0; x < 24; x++)
    {
      CU_ASSERT (pqueue_size (pqueue_min) == 36 - x);
      CU_ASSERT (pqueue_size (pqueue_max) == 36 - x);
      CU_ASSERT (pqueue_size (pqueue_heap) == 36 - x);

      cur = pqueue_dequeue (pqueue_min);
      CU_ASSERT (cur != NULL);
      CU_ASSERT (*cur == (x % 3) + 7);
      free (cur);
      
      cur = pqueue_dequeue (pqueue_max);
      CU_ASSERT (cur != NULL);
      CU_ASSERT (*cur == (x % 3) + 7);
      free (cur);

      cur = pqueue_dequeue (pqueue_heap);
      CU_ASSERT (cur != NULL);
      free (cur);
      
    }

  for (x = 0; x < 2; x++)
    {
      for (y = 1; y <= 3; y++)
	{
	  cur = pqueue_dequeue (pqueue_min);
	  CU_ASSERT (cur != NULL);
	  CU_ASSERT (*cur == y);
	  free (cur);
	  
	  cur = pqueue_dequeue (pqueue_max);
	  CU_ASSERT (cur != NULL);
	  CU_ASSERT (*cur == y);
	  free (cur);

	  cur = pqueue_dequeue (pqueue_heap);
	  CU_ASSERT (cur != NULL);
	  free (cur);
	}

      for (y = 7; y <= 9; y++)
	{
	  cur = pqueue_dequeue (pqueue_min);
	  CU_ASSERT (cur != NULL);
	  CU_ASSERT (*cur == y);
	  free (cur);
	  
	  cur = pqueue_dequeue (pqueue_max);
	  CU_ASSERT (cur != NULL);
	  CU_ASSERT (*cur == y);
	  free (cur);

	  cur = pqueue_dequeue (pqueue_heap);
	  CU_ASSERT (cur != NULL);
	  free (cur);
	}
    }

  CU_ASSERT (pqueue_dequeue (pqueue_min) == NULL);
  CU_ASSERT (pqueue_dequeue (pqueue_max) == NULL);
  CU_ASSERT (pqueue_dequeue (pqueue_heap) == NULL);
}

int
make_pqueue_suite (CU_pSuite s)
{
  s = CU_add_suite ("Test Pqueue Suite", 
		    init_test_pqueue_suite, 
		    clean_test_pqueue_suite);
  if (s == NULL)
    {
      return CU_get_error(); 
    }

  if (CU_add_test (s, "test_pqueue_enqueue", test_pqueue_enqueue) == NULL ||
      CU_add_test (s, "test_pqueue_peek", 
		   test_pqueue_peek) == NULL ||
      CU_add_test (s, "test_pqueue_dequeue", 
		   test_pqueue_dequeue) == NULL ||
      CU_add_test (s, "test_pqueue_enqueue2", 
		   test_pqueue_enqueue2) == NULL ||
      CU_add_test (s, "test_pqueue_dequeue2", 
		   test_pqueue_dequeue2) == NULL)
    {
      return CU_get_error();
    }

  return CU_get_error();
}


